import java.util.*;
import java_cup.runtime.*;

%%

%{
    private Symbol symbol(int type, String name) {
		return new Symbol(type, yyline+1, yycolumn);
    }
%}

%x ST_IN_SCRIPTING
%x ST_DOUBLE_QUOTES
%x ST_SINGLE_QUOTE
%x ST_LOOKING_FOR_PROPERTY
%x ST_LOOKING_FOR_VARNAME
%x ST_COMMENT
%x ST_ONE_LINE_COMMENT

LNUM = [0-9]+
DNUM = ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
EXPONENT_DNUM = (({LNUM}|{DNUM})[eE][+\-]?{LNUM})
HNUM = "0x"[0-9a-fA-F]+
LABEL = [a-zA-Z_\x7f-\xbb\xbc-\xde\xdf-\xff][a-zA-Z0-9_\x7f-\xbb\xbc-\xde\xdf-\xff]*
WHITESPACE = [ \n\r\t]+
TABS_AND_SPACES = [ \t]*
ESCAPED_AND_WHITESPACE = [\n\t\r #'.:;,()|\^&+\-/*=%!~<>?@]+
ANY_CHAR = (.|[\n])
NEWLINE = ("\r"|"\n"|"\r\n")

%cupsym PhpSymbols
%class PhpLexer
%ignorecase
%unicode
%public
%column
%line
%cup

%%

<YYINITIAL>"<?php"([ \t]|{NEWLINE}) { yybegin(ST_IN_SCRIPTING); }
<ST_IN_SCRIPTING>"exit" { return symbol(PhpSymbols.T_EXIT, "T_EXIT"); }
<ST_IN_SCRIPTING>"die" {  return symbol(PhpSymbols.T_EXIT, "T_EXIT"); }
<ST_IN_SCRIPTING>"function"|"cfunction" { return symbol(PhpSymbols.T_FUNCTION, "T_FUNCTION"); }
<ST_IN_SCRIPTING>"const" { return symbol(PhpSymbols.T_CONST, "T_CONST"); }
<ST_IN_SCRIPTING>"return" { return symbol(PhpSymbols.T_RETURN, "T_RETURN"); }
<ST_IN_SCRIPTING>"if" { return symbol(PhpSymbols.T_IF, "T_IF"); }
<ST_IN_SCRIPTING>"elseif" { return symbol(PhpSymbols.T_ELSEIF, "T_ELSEIF"); }
<ST_IN_SCRIPTING>"endif" { return symbol(PhpSymbols.T_ENDIF, "T_ENDIF"); }
<ST_IN_SCRIPTING>"else" { return symbol(PhpSymbols.T_ELSE, "T_ELSE"); }
<ST_IN_SCRIPTING>"while" { return symbol(PhpSymbols.T_WHILE, "T_WHILE"); }
<ST_IN_SCRIPTING>"endwhile" { return symbol(PhpSymbols.T_ENDWHILE, "T_ENDWHILE"); }
<ST_IN_SCRIPTING>"do" { return symbol(PhpSymbols.T_DO, "T_DO"); }
<ST_IN_SCRIPTING>"for" { return symbol(PhpSymbols.T_FOR, "T_FOR"); }
<ST_IN_SCRIPTING>"endfor" { return symbol(PhpSymbols.T_ENDFOR, "T_ENDFOR"); }
<ST_IN_SCRIPTING>"foreach" { return symbol(PhpSymbols.T_FOREACH, "T_FOREACH"); }
<ST_IN_SCRIPTING>"endforeach" { return symbol(PhpSymbols.T_ENDFOREACH, "T_ENDFOREACH"); }
<ST_IN_SCRIPTING>"as" { return symbol(PhpSymbols.T_AS, "T_AS"); }
<ST_IN_SCRIPTING>"switch" { return symbol(PhpSymbols.T_SWITCH, "T_SWITCH"); }
<ST_IN_SCRIPTING>"endswitch" { return symbol(PhpSymbols.T_ENDSWITCH, "T_ENDSWITCH"); }
<ST_IN_SCRIPTING>"case" { return symbol(PhpSymbols.T_CASE, "T_CASE"); }
<ST_IN_SCRIPTING>"default" { return symbol(PhpSymbols.T_DEFAULT, "T_DEFAULT"); }
<ST_IN_SCRIPTING>"break" { return symbol(PhpSymbols.T_BREAK, "T_BREAK"); }
<ST_IN_SCRIPTING>"continue" { return symbol(PhpSymbols.T_CONTINUE, "T_CONTINUE"); }
<ST_IN_SCRIPTING>"echo" { return symbol(PhpSymbols.T_ECHO, "T_ECHO"); }
<ST_IN_SCRIPTING>"print" { return symbol(PhpSymbols.T_PRINT, "T_PRINT"); }
<ST_LOOKING_FOR_PROPERTY>{LABEL} { return symbol(PhpSymbols.T_STRING, "T_STRING"); }
<ST_LOOKING_FOR_PROPERTY>{ANY_CHAR} { }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("int"|"integer"){TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_INT_CAST, "T_INT_CAST"); }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("real"|"double"|"float"){TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_DOUBLE_CAST, "T_DOUBLE_CAST"); }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"string"{TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_STRING_CAST, "T_STRING_CAST"); }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_ARRAY_CAST, "T_ARRAY_CAST"); }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"object"{TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_OBJECT_CAST, "T_OBJECT_CAST"); }
<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("bool"|"boolean"){TABS_AND_SPACES}")" { return symbol(PhpSymbols.T_BOOL_CAST, "T_BOOL_CAST"); }
<ST_IN_SCRIPTING>"global" { return symbol(PhpSymbols.T_GLOBAL, "T_GLOBAL"); }
<ST_IN_SCRIPTING>"=>" { return symbol(PhpSymbols.T_DOUBLE_ARROW, "T_DOUBLE_ARROW"); }
<ST_IN_SCRIPTING>"list" { return symbol(PhpSymbols.T_LIST, "T_LIST"); }
<ST_IN_SCRIPTING>"array" { return symbol(PhpSymbols.T_ARRAY, "T_ARRAY"); }
<ST_IN_SCRIPTING>"++" { return symbol(PhpSymbols.T_INC, "T_INC"); }
<ST_IN_SCRIPTING>"--" { return symbol(PhpSymbols.T_DEC, "T_DEC"); }
<ST_IN_SCRIPTING>"===" { return symbol(PhpSymbols.T_IS_IDENTICAL, "T_IS_IDENTICAL"); }
<ST_IN_SCRIPTING>"!==" { return symbol(PhpSymbols.T_IS_NOT_IDENTICAL, "T_IS_NOT_IDENTICAL"); }
<ST_IN_SCRIPTING>"==" { return symbol(PhpSymbols.T_IS_EQUAL, "T_IS_EQUAL"); }
<ST_IN_SCRIPTING>"!="|"<>" { return symbol(PhpSymbols.T_IS_NOT_EQUAL, "T_IS_NOT_EQUAL"); }
<ST_IN_SCRIPTING>"<=" { return symbol(PhpSymbols.T_IS_SMALLER_OR_EQUAL, "T_IS_SMALLER_OR_EQUAL"); }
<ST_IN_SCRIPTING>">=" { return symbol(PhpSymbols.T_IS_GREATER_OR_EQUAL, "T_IS_GREATER_OR_EQUAL"); }
<ST_IN_SCRIPTING>"+=" { return symbol(PhpSymbols.T_PLUS_EQUAL, "T_PLUS_EQUAL"); }
<ST_IN_SCRIPTING>"-=" { return symbol(PhpSymbols.T_MINUS_EQUAL, "T_MINUS_EQUAL"); }
<ST_IN_SCRIPTING>"*=" { return symbol(PhpSymbols.T_MUL_EQUAL, "T_MUL_EQUAL"); }
<ST_IN_SCRIPTING>"/=" { return symbol(PhpSymbols.T_DIV_EQUAL, "T_DIV_EQUAL"); }
<ST_IN_SCRIPTING>".=" { return symbol(PhpSymbols.T_CONCAT_EQUAL, "T_CONCAT_EQUAL"); }
<ST_IN_SCRIPTING>"%=" { return symbol(PhpSymbols.T_MOD_EQUAL, "T_MOD_EQUAL"); }
<ST_IN_SCRIPTING>"<<=" { return symbol(PhpSymbols.T_SL_EQUAL, "T_SL_EQUAL"); }
<ST_IN_SCRIPTING>">>=" { return symbol(PhpSymbols.T_SR_EQUAL, "T_SR_EQUAL"); }
<ST_IN_SCRIPTING>"&=" { return symbol(PhpSymbols.T_AND_EQUAL, "T_AND_EQUAL"); }
<ST_IN_SCRIPTING>"|=" { return symbol(PhpSymbols.T_OR_EQUAL, "T_OR_EQUAL"); }
<ST_IN_SCRIPTING>"^=" { return symbol(PhpSymbols.T_XOR_EQUAL, "T_XOR_EQUAL"); }
<ST_IN_SCRIPTING>"||" { return symbol(PhpSymbols.T_BOOLEAN_OR, "T_BOOLEAN_OR"); }
<ST_IN_SCRIPTING>"&&" { return symbol(PhpSymbols.T_BOOLEAN_AND, "T_BOOLEAN_AND"); }
<ST_IN_SCRIPTING>"OR" { return symbol(PhpSymbols.T_LOGICAL_OR, "T_LOGICAL_OR"); }
<ST_IN_SCRIPTING>"AND" { return symbol(PhpSymbols.T_LOGICAL_AND, "T_LOGICAL_AND"); }
<ST_IN_SCRIPTING>"XOR" { return symbol(PhpSymbols.T_LOGICAL_XOR, "T_LOGICAL_XOR"); }
<ST_IN_SCRIPTING>"<<" { return symbol(PhpSymbols.T_SL, "T_SL"); }
<ST_IN_SCRIPTING>">>" { return symbol(PhpSymbols.T_SR, "T_SR"); }
<ST_IN_SCRIPTING> {
    ";" { return symbol(PhpSymbols.T_SEMICOLON, "T_SEMICOLON"); }
    ":" { return symbol(PhpSymbols.T_COLON, "T_COLON"); }
    "," { return symbol(PhpSymbols.T_COMMA, "T_COMMA"); }
    "." { return symbol(PhpSymbols.T_POINT, "T_POINT"); }
    "[" { return symbol(PhpSymbols.T_OPEN_RECT_BRACES, "T_OPEN_RECT_BRACES"); }
    "]" { return symbol(PhpSymbols.T_CLOSE_RECT_BRACES, "T_CLOSE_RECT_BRACES"); }
    "(" { return symbol(PhpSymbols.T_OPEN_BRACES, "T_OPEN_BRACES"); }
    ")" { return symbol(PhpSymbols.T_CLOSE_BRACES, "T_CLOSE_BRACES"); }
    "|" { return symbol(PhpSymbols.T_BITWISE_OR, "T_BITWISE_OR"); }
    "^" { return symbol(PhpSymbols.T_BITWISE_XOR, "T_BITWISE_XOR"); }
    "&" { return symbol(PhpSymbols.T_BITWISE_AND, "T_BITWISE_AND"); }
    "+" { return symbol(PhpSymbols.T_PLUS, "T_PLUS"); }
    "-" { return symbol(PhpSymbols.T_MINUS, "T_MINUS"); }
    "/" { return symbol(PhpSymbols.T_DIV, "T_DIV"); }
    "*" { return symbol(PhpSymbols.T_MULT, "T_MULT"); }
    "=" { return symbol(PhpSymbols.T_ASSIGN, "T_ASSIGN"); }
    "%" { return symbol(PhpSymbols.T_MODULO, "T_MODULO"); }
    "!" { return symbol(PhpSymbols.T_NOT, "T_NOT"); }
    "~" { return symbol(PhpSymbols.T_BITWISE_NOT, "T_BITWISE_NOT"); }
    "$" { return symbol(PhpSymbols.T_DOLLAR, "T_DOLLAR"); }
    "<" { return symbol(PhpSymbols.T_IS_SMALLER, "T_IS_SMALLER"); }
    ">" { return symbol(PhpSymbols.T_IS_GREATER, "T_IS_GREATER"); }
    "?" { return symbol(PhpSymbols.T_QUESTION, "T_QUESTION"); }
    "@" { return symbol(PhpSymbols.T_AT, "T_AT"); }
}
<ST_IN_SCRIPTING>"{" { return symbol(PhpSymbols.T_OPEN_CURLY_BRACES, "T_OPEN_CURLY_BRACES"); }
<ST_DOUBLE_QUOTES>"${" { return symbol(PhpSymbols.T_DOLLAR_OPEN_CURLY_BRACES, "T_DOLLAR_OPEN_CURLY_BRACES"); }
<ST_IN_SCRIPTING>"}" { return symbol(PhpSymbols.T_CLOSE_CURLY_BRACES, "T_CLOSE_CURLY_BRACES"); }
<ST_LOOKING_FOR_VARNAME>{LABEL} { return symbol(PhpSymbols.T_STRING_VARNAME, "T_STRING_VARNAME"); }
<ST_LOOKING_FOR_VARNAME>{ANY_CHAR} { }
<ST_IN_SCRIPTING>{LNUM} { return symbol(PhpSymbols.T_LNUMBER, "T_LNUMBER"); }
<ST_IN_SCRIPTING>{HNUM} { return symbol(PhpSymbols.T_LNUMBER, "T_LNUMBER"); }
<ST_DOUBLE_QUOTES>{LNUM}|{HNUM} { return symbol(PhpSymbols.T_NUM_STRING, "T_NUM_STRING"); }
<ST_IN_SCRIPTING>{DNUM}|{EXPONENT_DNUM} { return symbol(PhpSymbols.T_DNUMBER, "T_DNUMBER"); }
<ST_IN_SCRIPTING,ST_DOUBLE_QUOTES>"$"{LABEL} { return symbol(PhpSymbols.T_VARIABLE, "T_VARIABLE"); }
<ST_IN_SCRIPTING>{LABEL} { return symbol(PhpSymbols.T_STRING, "T_STRING"); }
<ST_DOUBLE_QUOTES>{LABEL} { return symbol(PhpSymbols.T_STRING, "T_STRING"); }
<ST_IN_SCRIPTING>{WHITESPACE} { }
<ST_IN_SCRIPTING>"#"|"//" { yybegin(ST_ONE_LINE_COMMENT); }
<ST_ONE_LINE_COMMENT>"?"|"%"|">" { }
<ST_ONE_LINE_COMMENT>[^\n\r?%>]+ { }
<ST_ONE_LINE_COMMENT>{NEWLINE} { yybegin(ST_IN_SCRIPTING); }
<ST_ONE_LINE_COMMENT>"?>"|"%>" { yybegin(ST_IN_SCRIPTING); }
<ST_IN_SCRIPTING>"/*" { yybegin(ST_COMMENT); }
<ST_COMMENT>[^*]+ { }
<ST_COMMENT>"*/" { yybegin(ST_IN_SCRIPTING); }
<ST_COMMENT>"*" { }
<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? { yybegin(YYINITIAL); return symbol(PhpSymbols.T_SEMICOLON, "T_SEMICOLON"); }
<ST_IN_SCRIPTING>"%>"{NEWLINE}? { yybegin(YYINITIAL); return symbol(PhpSymbols.T_SEMICOLON, "T_SEMICOLON"); }
<ST_IN_SCRIPTING>([\"]([^$\"\\]|("\\".))*[\"]) { return symbol(PhpSymbols.T_CONSTANT_ENCAPSED_STRING, "T_CONSTANT_ENCAPSED_STRING"); }
<ST_IN_SCRIPTING>([']([^'\\]|("\\".))*[']) { return symbol(PhpSymbols.T_CONSTANT_ENCAPSED_STRING, "T_CONSTANT_ENCAPSED_STRING"); }
<ST_IN_SCRIPTING>[\"] { yybegin(ST_DOUBLE_QUOTES); return symbol(PhpSymbols.T_DOUBLE_QUOTE, "T_DOUBLE_QUOTE"); }
<ST_IN_SCRIPTING>['] { yybegin(ST_SINGLE_QUOTE); return symbol(PhpSymbols.T_SINGLE_QUOTE, "T_SINGLE_QUOTE"); }
<ST_DOUBLE_QUOTES>{ESCAPED_AND_WHITESPACE} { return symbol(PhpSymbols.T_ENCAPSED_AND_WHITESPACE, "T_ENCAPSED_AND_WHITESPACE"); }
<ST_SINGLE_QUOTE>([^'\\]|\\[^'\\])+ { return symbol(PhpSymbols.T_ENCAPSED_AND_WHITESPACE, "T_ENCAPSED_AND_WHITESPACE"); }
<ST_DOUBLE_QUOTES>[`]+ { return symbol(PhpSymbols.T_ENCAPSED_AND_WHITESPACE, "T_ENCAPSED_AND_WHITESPACE"); }
<ST_DOUBLE_QUOTES>"$"[^a-zA-Z_\x7f-\xbb\xbc-\xde\xdf-\xff{] { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES> {
    "[" { return symbol(PhpSymbols.T_OPEN_RECT_BRACES, "T_OPEN_RECT_BRACES"); }
    "]" { return symbol(PhpSymbols.T_CLOSE_RECT_BRACES, "T_CLOSE_RECT_BRACES"); }
    "{" { return symbol(PhpSymbols.T_OPEN_CURLY_BRACES, "T_OPEN_CURLY_BRACES"); }
    "}" { return symbol(PhpSymbols.T_CLOSE_CURLY_BRACES, "T_CLOSE_CURLY_BRACES"); }
    "$" { return symbol(PhpSymbols.T_DOLLAR, "T_DOLLAR"); }
}
<ST_DOUBLE_QUOTES>"{$" { return symbol(PhpSymbols.T_CURLY_OPEN, "T_CURLY_OPEN"); }
<ST_SINGLE_QUOTE>"\\'" { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_SINGLE_QUOTE>"\\\\" { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES>"\\\"" { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES>"\\"[0-7]{1,3} { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES>"\\x"[0-9A-Fa-f]{1,2} { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES>"\\"{ANY_CHAR} { return symbol(PhpSymbols.T_CHARACTER, "T_CHARACTER"); }
<ST_DOUBLE_QUOTES>[\"] { yybegin(ST_IN_SCRIPTING); return symbol(PhpSymbols.T_DOUBLE_QUOTE, "T_DOUBLE_QUOTE"); }
<ST_SINGLE_QUOTE>['] { yybegin(ST_IN_SCRIPTING); return symbol(PhpSymbols.T_SINGLE_QUOTE, "T_SINGLE_QUOTE"); }
<ST_DOUBLE_QUOTES,YYINITIAL,ST_IN_SCRIPTING,ST_LOOKING_FOR_PROPERTY><<EOF>> { return null; }
<ST_COMMENT><<EOF>> { return null; }
<ST_IN_SCRIPTING,YYINITIAL,ST_DOUBLE_QUOTES,ST_SINGLE_QUOTE>{ANY_CHAR} { return null; }